#region Using Statements
using System;
using System.Collections.Generic;//using System.Xml.Serialization;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
#endregion

namespace Pauliver
{
    public abstract class BaseCollision
    {
        public BaseCollision()
        {

        }

        protected const float MAXFLOAT = 1000000;

        public virtual void ObjectOnObjectCollision()
        {
            foreach (GameObject g1 in Game1.Instance.GameManager.SceneGraph)
            {
                if (g1[ComponentType.Collidable] != null)
                {
                    if ((g1[ComponentType.Collidable] as Collidable).Moving)
                    {
                        foreach (GameObject g2 in Game1.Instance.GameManager.SceneGraph)
                        {
                            if (!g1.Equals(g2))
                            {
                                if (g2[ComponentType.Collidable] != null)
                                {
                                    if ((g1[ComponentType.Collidable] as Collidable).GetBoundingBox.Intersects((g2[ComponentType.Collidable] as Collidable).GetBoundingBox))
                                    {
                                        List<Vector2> Points = new List<Vector2>();
                                        if ((g1[ComponentType.Collidable] as Collidable).IntersectPixels(g2, out Points))
                                        {
                                            if (g1[ComponentType.CollisionCallback] != null)
                                            {
                                                (g1[ComponentType.CollisionCallback] as CollisionCallback).OnCollision(g2);
                                            }
                                            if (g2[ComponentType.CollisionCallback] != null)
                                            {
                                                (g2[ComponentType.CollisionCallback] as CollisionCallback).OnCollision(g1);
                                            }


                                            bool Move = false;
                                            //=========================================================
                                            {
                                                Collidable_Animal c1;
                                                Type_Animal c2;

                                                if (g1.GetComponent<Collidable_Animal>(ComponentType.Collidable_Animal, out c1) && g2.GetComponent<Type_Animal>(ComponentType.Type_Animal, out c2))
                                                {
                                                    Move = true;
                                                }
                                            }
                                            {
                                                Collidable_Weapon c1;
                                                Type_Weapon c2;

                                                if (g1.GetComponent<Collidable_Weapon>(ComponentType.Collidable_Weapon, out c1) && g2.GetComponent<Type_Weapon>(ComponentType.Type_Weapon, out c2))
                                                {
                                                    //don't move him, EXPLODE
                                                }
                                            }
                                            //=========================================================
                                            if (Move)
                                            {
                                                Vector2 position1 = (g1[ComponentType.Game_Position] as Game_Position).Position;
                                                Vector2 position2 = (g2[ComponentType.Game_Position] as Game_Position).Position;
                                                Vector2 MidPoint1 = new Vector2((g1[ComponentType.Collidable] as Collidable).Width / 2, (g2[ComponentType.Collidable] as Collidable).Height / 2);
                                                Vector2 MidPoint2 = new Vector2((g2[ComponentType.Collidable] as Collidable).Width / 2, (g2[ComponentType.Collidable] as Collidable).Height / 2);
                                                Vector2 Center1 = position1 + MidPoint1;
                                                Vector2 Center2 = position2 + MidPoint2;
                                                float smallestX = MAXFLOAT, biggestX = 0;
                                                float smallestY = MAXFLOAT, biggestY = 0;
                                                foreach (Vector2 v in Points)
                                                {
                                                    foreach (Vector2 v2 in Points)
                                                    {
                                                        if (v.Y == v2.Y)
                                                        {
                                                            if (v.X <= smallestX)
                                                                smallestX = v.X;
                                                            if (v.X >= biggestX)
                                                                biggestX = v.X;
                                                        }
                                                        if (v.X == v2.X)
                                                        {
                                                            if (v.Y <= smallestY)
                                                                smallestY = v.Y;
                                                            if (v.Y >= biggestY)
                                                                biggestY = v.Y;
                                                        }
                                                    }
                                                }
                                                float Xthickness = biggestX - smallestX;
                                                float Ythickness = biggestY - smallestY;
                                                smallestX = MAXFLOAT; biggestX = 0;
                                                smallestY = MAXFLOAT; biggestY = 0;
                                                bool left = false;
                                                bool right = false;
                                                bool top = false;
                                                bool bottom = false;
                                                foreach (Vector2 v in Points)
                                                {
                                                    if (v.X <= smallestX)
                                                        smallestX = v.X;
                                                    if (v.Y <= smallestY)
                                                        smallestY = v.Y;
                                                    if (v.X >= biggestX)
                                                        biggestX = v.X;
                                                    if (v.Y >= biggestY)
                                                        biggestY = v.Y;

                                                    {
                                                        Vector2 tempVector = ((Vector2)(position2 + v));
                                                        if (tempVector.X < position1.X)
                                                        {
                                                            left = true;
                                                        }
                                                        if (tempVector.Y < position1.Y)
                                                        {
                                                            bottom = true;
                                                        }
                                                        if (tempVector.X > position1.X)
                                                        {
                                                            right = true;
                                                        }
                                                        if (tempVector.Y > position1.Y)
                                                        {
                                                            top = true;
                                                        }
                                                    }
                                                }
                                                Vector2 lineCrossed = new Vector2(biggestX - smallestX, biggestY - smallestY);

                                                Vector2 AddMe = Vector2.Zero;
                                                if (lineCrossed.X > lineCrossed.Y)
                                                {
                                                    if (left)
                                                    {
                                                        //Move Right
                                                        AddMe.X -= (lineCrossed.X + 1);
                                                    }
                                                    else if (right)
                                                    {
                                                        //Move Left
                                                        AddMe.X += (lineCrossed.X + 1);
                                                    }
                                                    System.Diagnostics.Debug.Assert(!(left == false && right == false));
                                                }
                                                else //if(lineCrossed.Y > lineCrossed.X)
                                                {
                                                    if (bottom)
                                                    {
                                                        //Move Up
                                                        AddMe.Y += (lineCrossed.Y + 1);
                                                    }
                                                    else if (top)
                                                    {
                                                        //Move Down
                                                        AddMe.Y -= lineCrossed.Y;
                                                    }
                                                    System.Diagnostics.Debug.Assert(!(top == false && bottom == false));
                                                }

                                                //if (g1[ComponentType.Settled_Object] != null && (top || bottom))
                                                //{
                                                //    (g1[ComponentType.Settled_Object] as Settled_Object).Settled = true;
                                                //    (g1[ComponentType.Settled_Object] as Settled_Object).SettledOn = (g2[ComponentType.Game_Position] as Game_Position);
                                                //}
                                                (g1[ComponentType.Collidable] as Collidable).Moving = false;
                                                (g1[ComponentType.Game_Velocity] as Game_Velocity).Velocity = Vector2.Zero;
                                                (g1[ComponentType.Game_Position] as Game_Position).Position += AddMe;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        public virtual void ManageCollisionAgainstTerrain(GameObject gameObject, List<Vector2> Points)
        {
            if (gameObject[ComponentType.CollisionCallback] != null)
            {
                (gameObject[ComponentType.CollisionCallback] as CollisionCallback).OnCollision(gameObject);
            }
            if (gameObject[ComponentType.Game_Velocity] != null)
            {
                (gameObject[ComponentType.Game_Velocity] as Game_Velocity).Velocity = Vector2.Zero;
            }
            if (gameObject[ComponentType.Settled_Ground] != null)
            {
                (gameObject[ComponentType.Settled_Ground] as Settled_Ground).Settled = true;
            }
            (gameObject[ComponentType.Collidable] as Collidable).Moving = false;

            Game_Position Position = (gameObject[ComponentType.Game_Position] as Game_Position);
            float smallestX = MAXFLOAT, biggestX = 0;
            float smallestY = MAXFLOAT, biggestY = 0;
            Vector2 sx = Points[0], lx = Points[0];
            foreach (Vector2 v in Points)
            {
                foreach (Vector2 v2 in Points)
                {
                    if (v.Y == v2.Y)
                    {
                        if (v.X <= smallestX)
                        {
                            smallestX = v.X;
                            sx = v;
                        }
                        if (v.X >= biggestX)
                        {
                            biggestX = v.X;
                            lx = v;
                        }
                    }
                    if (v.X == v2.X)
                    {
                        if (v.Y <= smallestY)
                            smallestY = v.Y;
                        if (v.Y >= biggestY)
                            biggestY = v.Y;
                    }
                }
            }
            float Xthickness = biggestX - smallestX;
            float Ythickness = biggestY - smallestY;

            smallestX = MAXFLOAT; biggestX = 0;
            smallestY = MAXFLOAT; biggestY = 0;
            foreach (Vector2 v in Points)
            {
                if (v.X <= smallestX)
                    smallestX = v.X;
                if (v.Y <= smallestY)
                    smallestY = v.Y;
                if (v.X >= biggestX)
                    biggestX = v.X;
                if (v.Y >= biggestY)
                    biggestY = v.Y;
            }
            if ((Math.Abs(Ythickness) / Math.Abs(Xthickness)) > 1.25)
            {
                Position.Y -= Ythickness;
            }
            else
            {
                Position.Y -= Ythickness;
            }
        }

        public virtual void ObjectOnTerrainCollision()
        {

            foreach (GameObject gameObject in Game1.Instance.GameManager.SceneGraph)
            {
                Vector2 Position = ((Game_Position)gameObject[ComponentType.Game_Position]).Position;
                {
                    if (Position.X > Game1.Instance.World.X - 32)
                    {
                        if (gameObject is ProjectileObject)
                        {
                            Game1.Instance.GameManager.RemoveFromSceneGraph(gameObject);
                        }
                        else
                        {
                            ((Game_Position)gameObject[ComponentType.Game_Position]).X = Game1.Instance.World.X - 32;
                        }
                    }
                    else
                        if (Position.X < 1)
                        {
                            if (gameObject is ProjectileObject)
                            {
                                Game1.Instance.GameManager.RemoveFromSceneGraph(gameObject);
                            }
                            else
                            {
                                ((Game_Position)gameObject[ComponentType.Game_Position]).X = 1;
                            }
                        }
                    if (Position.Y > Game1.Instance.World.Y + 64)
                    {
                        if (gameObject is ProjectileObject || gameObject is PlayerObject)
                        {
                            Game1.Instance.GameManager.RemoveFromSceneGraph(gameObject);
                        }
                        else
                        {
                            ((Game_Position)gameObject[ComponentType.Game_Position]).Y = Game1.Instance.World.Y + 64;
                        }
                    }
                }



                if (gameObject[ComponentType.Settled_Ground] != null)
                {
                    if ((gameObject[ComponentType.Settled_Ground] as Settled_Ground).Settled == false)
                    {
                        if (gameObject[ComponentType.Collidable] != null)
                        {
                            if (gameObject[ComponentType.Collidable_Terrain] != null)
                            {
                                Collidable temp = (Collidable)gameObject[ComponentType.Collidable];
                                if (Game1.Instance.GameManager.Terrain.m_BoundingRectangle.Intersects(temp.GetBoundingBox))
                                {
                                    List<Vector2> Points = new List<Vector2>();
                                    if (temp.IntersectPixels(Game1.Instance.GameManager.Terrain.m_BoundingRectangle, Game1.Instance.GameManager.Terrain.m_TextureData, out Points))
                                    //if (this._terrain.IntersectPixels(gameObject, out Points))//need to be able to take a terrain in one of these
                                    {
                                        ManageCollisionAgainstTerrain(gameObject, Points);
                                    }
                                }

                            }
                        }
                    }
                }
                else if (gameObject[ComponentType.Collidable] != null)
                {
                    if (gameObject[ComponentType.Collidable_Terrain] != null)
                    {
                        if (Game1.Instance.GameManager.Terrain[(int)Position.X] < (Position.Y + 64)) //@@ should be plus .5 * height
                        {
                            Collidable temp = (Collidable)gameObject[ComponentType.Collidable];
                            if (Game1.Instance.GameManager.Terrain.m_BoundingRectangle.Intersects(temp.GetBoundingBox))
                            {
                                List<Vector2> Points = new List<Vector2>();
                                if (temp.IntersectPixels(Game1.Instance.GameManager.Terrain.m_BoundingRectangle, Game1.Instance.GameManager.Terrain.m_TextureData, out Points))
                                //if (this._terrain.IntersectPixels(gameObject, out Points))//need to be able to take a terrain in one of these
                                {
                                    ManageCollisionAgainstTerrain(gameObject, Points);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
